/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package com.unimod.fsmleditor.action;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.DeferredUpdateManager;
import org.eclipse.draw2d.UpdateManager;
import org.eclipse.gef.commands.Command;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.TextEditorAction;

import com.evelopers.unimod.plugin.eclipse.glayout.SimpleLayouter;
import com.evelopers.unimod.plugin.eclipse.glayout.converter.FastLayoutWrapper;
import com.evelopers.unimod.plugin.eclipse.layout.ConnectivityDiagramLayouter;
import com.evelopers.unimod.plugin.eclipse.layout.Layouter;
import com.evelopers.unimod.plugin.eclipse.model.GModel;
import com.evelopers.unimod.plugin.eclipse.model.GStateMachine;
import com.evelopers.unimod.plugin.eclipse.transform.gxml.GModelToGXML;
import com.evelopers.unimod.transform.TransformException;
import com.unimod.fsml.model.FSMLModelHelper;
import com.unimod.fsmleditor.FSMLEditorMessages;

/**
 * Generates UniMod xml file for automaton model of the specified FSML program.
 * 
 * @author Ivan Lagunov
 */
public class GenerateUniModXmlAction extends TextEditorAction {
    private static final Log log = LogFactory.getLog(GenerateUniModXmlAction.class);

	/**
	 * Constructs and updates the action.
	 */
	public GenerateUniModXmlAction(ITextEditor editor) {
		super(FSMLEditorMessages.getResourceBundle(), "GenerateUniModXml.", editor);
		update();
	}
	
	/* (non-Javadoc)
	 * Method declared on IAction
	 */
	@Override
    public void run() {
		ITextEditor editor = getTextEditor();
		FSMLModelHelper modelHelper = FSMLModelHelper.getInstance();

		IFile file = modelHelper.getUniModXml();
		if (null == file) {
			SaveAsDialog dialog = new SaveAsDialog(editor.getSite().getShell());
			dialog.setOriginalName(".unimod");
	        dialog.open();
	        IPath path = dialog.getResult();

	        if (path == null) {
	        	return;
	        }

	        file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
			modelHelper.setUniModXml(file);
		}

		ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(editor.getSite().getShell());
		progressMonitorDialog.open();
        IProgressMonitor progressMonitor = progressMonitorDialog.getProgressMonitor();
        try {
	        saveModelInXml(modelHelper.getProgramModel(), file, progressMonitor);
		} catch (CoreException e) {
	        ErrorDialog.openError(editor.getSite().getShell(), "Error During Save",
	                "The current workflow model could not be saved.", e.getStatus());
		}
		progressMonitorDialog.close();
	}
	
	/**
	 * Saves specified graphic model in the specified file.
	 * 
	 * @param model graphic model to save.
	 * @param file file descriptor to save in. 
	 * @param progressMonitor progress monitor 
	 * @throws CoreException
	 */
	private void saveModelInXml(GModel model, IFile file,
			IProgressMonitor progressMonitor) throws CoreException {
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			layoutModel(model);
			GModelToGXML.write(model, out);

			ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
			if (file.exists()) {
				file.setContents(in, true, true, progressMonitor);
			} else {
				file.create(in, true, progressMonitor);
			}
		} catch (TransformException e) {
			log.error("Cannot transform automaton model into xml", e);
		}
	}
	
	/**
	 * Performs simple layout of given model.
	 * Puts vertices into grid.
	 * 
	 * @param model graphic model to layout.
	 */
	private void simpleLayoutModel(GModel model) {
		SimpleLayouter.getInstance().layoutModel(model);
	}
	
	/**
	 * Performs layout of given model.
	 * 
	 * @param model graphic model to layout.
	 */
	private void layoutModel(GModel model) {
		layoutConnectivityPage(model);
		layoutStatechartPage(model);
	}
	
	/**
	 * Layouts connectivity diagram of given model.
	 * 
	 * @param model graphic model to layout.
	 */
	private void layoutConnectivityPage(GModel model) {
	    Layouter l = ConnectivityDiagramLayouter.create(model);
	    
	    Command c = l.layout();
	    c.execute();
	}

	/**
	 * Layouts statechart diagram of given model.
	 * 
	 * @param model graphic model to layout.
	 */
	private void layoutStatechartPage(GModel model) {
        try {
            Shell shell = getTextEditor().getSite().getShell();
            ProgressMonitorDialog pmd = new ProgressMonitorDialog(shell);
    		UpdateManager updateManager = new DeferredUpdateManager();

            for (Object o : model.getStateMachines()) {
                GStateMachine gsm = (GStateMachine) o;
            	
                FastLayoutWrapper lp = new FastLayoutWrapper(gsm, updateManager);
                pmd.run(true, true, lp);
                lp.getC().execute();
                pmd.close();
            }
        } catch (Exception e) {
        	log.error("Cannot layout statechart diagram", e);
        }
	}
}
